{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "4c87bc55-5547-4079-a6d8-41e8198d2356",
   "metadata": {},
   "source": [
    "# 快速入门 Assistants API \n",
    "\n",
    "Assistants API 允许您在自己的应用程序中构建人工智能助手。一个助手有其指令，并可以利用模型、工具和知识来回应用户查询。\n",
    "\n",
    "Assistants API 目前支持三种类型的工具：\n",
    "- 代码解释器 Code Interpreter\n",
    "- 检索 Retrieval\n",
    "- 函数调用 Function calling\n",
    "\n",
    "使用 [Playground](https://platform.openai.com/playground?mode=assistant) 可以在线探索和测试 Assistants API 功能。\n",
    "\n",
    "本入门指南将指导您完成创建和运行使用代码解释器的助手的关键步骤，以下是使用 Assistants API 标准流程：\n",
    "1. 通过定义其自定义指令并选择 LLM 来创建一个助手(Assistant)。如果有需求，可以添加文件并启用诸如代码解释器、检索和函数调用等工具。\n",
    "2. 当用户开始对话时，创建一个线程(Thread)。\n",
    "3. 当用户提问时，向线程添加消息(Messages)。\n",
    "4. 通过调用模型和工具在线程上运行助手以生成响应。\n",
    "\n",
    "![assistans](images/diagram-assistant.png)\n",
    "\n",
    "OBJECT | WHAT IT REPRESENTS\n",
    "--- | ---\n",
    "Assistant | 专为特定目的构建的人工智能，使用 OpenAI 的模型并调用工具\n",
    "Thread | 助手与用户之间的对话会话。线程存储消息，并自动处理截断，以将内容适应模型的上下文。\n",
    "Message | 由助手或用户创建的消息。消息可以包括文本、图片和其他文件。消息以列表形式存储在线程上。\n",
    "Run | 在线程上对一个助手的调用。助手利用其配置和线程的消息执行任务，通过调用模型和工具。作为运行的一部分，助手会将消息追加到线程中。\n",
    "Run Step | 助手在运行中采取的详细步骤列表。助手可以在其运行期间调用工具或创建消息。检查运行步骤可以让您深入了解助手如何得出最终结果。\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b7a8bbea-2f1f-45a4-b3e8-929614c66790",
   "metadata": {},
   "source": [
    "\n",
    "## 使用 Assistants 开发数学辅导老师\n",
    "\n",
    "在这个示例中，我们正在创建一个数学辅导助手，并启用了代码解释器工具。\n",
    "\n",
    "### 第一步：创建助手"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "d2227bb3-179a-43c2-b389-60ecbd0dfce5",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Defaulting to user installation because normal site-packages is not writeable\n",
      "Requirement already satisfied: openai in c:\\users\\lenovo\\appdata\\roaming\\python\\python310\\site-packages (1.35.14)\n",
      "Requirement already satisfied: anyio<5,>=3.5.0 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from openai) (4.4.0)\n",
      "Requirement already satisfied: distro<2,>=1.7.0 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from openai) (1.9.0)\n",
      "Requirement already satisfied: httpx<1,>=0.23.0 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from openai) (0.27.0)\n",
      "Requirement already satisfied: pydantic<3,>=1.9.0 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from openai) (2.5.3)\n",
      "Requirement already satisfied: sniffio in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from openai) (1.3.1)\n",
      "Requirement already satisfied: tqdm>4 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from openai) (4.66.2)\n",
      "Requirement already satisfied: typing-extensions<5,>=4.7 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from openai) (4.12.2)\n",
      "Requirement already satisfied: idna>=2.8 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from anyio<5,>=3.5.0->openai) (3.6)\n",
      "Requirement already satisfied: exceptiongroup>=1.0.2 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from anyio<5,>=3.5.0->openai) (1.2.0)\n",
      "Requirement already satisfied: certifi in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from httpx<1,>=0.23.0->openai) (2024.2.2)\n",
      "Requirement already satisfied: httpcore==1.* in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from httpx<1,>=0.23.0->openai) (1.0.5)\n",
      "Requirement already satisfied: h11<0.15,>=0.13 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from httpcore==1.*->httpx<1,>=0.23.0->openai) (0.14.0)\n",
      "Requirement already satisfied: annotated-types>=0.4.0 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from pydantic<3,>=1.9.0->openai) (0.6.0)\n",
      "Requirement already satisfied: pydantic-core==2.14.6 in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from pydantic<3,>=1.9.0->openai) (2.14.6)\n",
      "Requirement already satisfied: colorama in c:\\programdata\\anaconda3\\envs\\langchain\\lib\\site-packages (from tqdm>4->openai) (0.4.6)\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))': /simple/openai/\n",
      "WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', ConnectionResetError(10054, '远程主机强迫关闭了一个现有的连接。', None, 10054, None))': /simple/openai/\n",
      "WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', ConnectionAbortedError(10053, '你的主机中的软件中止了一个已建立的连接。', None, 10053, None))': /simple/openai/\n",
      "WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', ConnectionAbortedError(10053, '你的主机中的软件中止了一个已建立的连接。', None, 10053, None))': /simple/openai/\n",
      "WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', ConnectionAbortedError(10053, '你的主机中的软件中止了一个已建立的连接。', None, 10053, None))': /simple/openai/\n"
     ]
    }
   ],
   "source": [
    "! pip install -U openai"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "052b55e0-8170-41de-a721-0961606c793e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import openai  # 导入 openai 库\n",
    "\n",
    "# 从环境变量 OPENAI_API_KEY 中获取 API 密钥\n",
    "client = openai.OpenAI()\n",
    "\n",
    "# 创建一个名为 \"Math Tutor\" 的助手，它是一个个人数学辅导老师。这个助手能够编写并运行代码来解答数学问题。\n",
    "assistant = client.beta.assistants.create(\n",
    "    name=\"Math Tutor\",\n",
    "    instructions=\"You are a personal math tutor. Write and run code to answer math questions.\",\n",
    "    tools=[{\"type\": \"code_interpreter\"}],  # 使用工具：代码解释器\n",
    "    model=\"gpt-4o\",  # 使用模型： GPT-4o\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1106c286-aa3b-4076-9992-37b1a56743c6",
   "metadata": {},
   "source": [
    "### 第二步：创建线程\n",
    "\n",
    "一个线程代表用户和一个或多个助手之间的对话。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "d1c7e57e-8e95-4411-ae53-0ae3ac004c62",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 创建一个交流线程\n",
    "thread = client.beta.threads.create()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b958896-d802-445e-8098-0a443399cf43",
   "metadata": {},
   "source": [
    "### 第三步：往线程添加消息\n",
    "\n",
    "用户或APP创建的消息内容将作为消息对象（Message Object）添加到线程中。 \n",
    "\n",
    "消息可以包含文本和文件，向线程添加的消息数量没有限制 - OpenAI 会智能地截断任何不适合模型上下文窗口的内容。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "f372ca8f-53be-4c3c-9e0a-c1b41b8955e7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在该线程中创建一条用户消息，并提交一个数学问题：“我需要解方程 `3x + 11 = 14`。你能帮忙吗？”\n",
    "message = client.beta.threads.messages.create(\n",
    "    thread_id=thread.id,\n",
    "    role=\"user\",\n",
    "    content=\"I need to solve the equation `3x + 11 = 14`. Can you help me?\",\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4c525954-63ef-44b1-94de-75a5b43568da",
   "metadata": {},
   "source": [
    "### 第四步：调用助手\n",
    "\n",
    "一旦所有用户消息都添加到了线程中，你可以使用任何助手运行该线程。\n",
    "\n",
    "创建一个运行会使用与助手相关的模型和工具来生成响应。这些响应将作为助手消息添加到线程中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "7a77c01e-7a68-41da-909b-d8e675a50d26",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Run completed with status: completed\n",
      "\n",
      "Messages:\n",
      "\n",
      "Role: Assistant\n",
      "Message:\n",
      "Of course, Jane Doe! Let's solve the equation step by step.\n",
      "\n",
      "The equation is:\n",
      "\n",
      "\\[ 3x + 11 = 14 \\]\n",
      "\n",
      "To isolate \\( x \\), follow these steps:\n",
      "\n",
      "1. Subtract 11 from both sides of the equation:\n",
      "\\[ 3x + 11 - 11 = 14 - 11 \\]\n",
      "\\[ 3x = 3 \\]\n",
      "\n",
      "2. Divide both sides by 3:\n",
      "\\[ \\frac{3x}{3} = \\frac{3}{3} \\]\n",
      "\\[ x = 1 \\]\n",
      "\n",
      "The solution to the equation \\( 3x + 11 = 14 \\) is \\( x = 1 \\).\n",
      "\n",
      "Role: User\n",
      "Message:\n",
      "I need to solve the equation `3x + 11 = 14`. Can you help me?\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 创建并等待执行流完成，用于处理该线程中的交互和问题解答\n",
    "run = client.beta.threads.runs.create_and_poll(\n",
    "    thread_id=thread.id,\n",
    "    assistant_id=assistant.id,\n",
    "    instructions=\"Please address the user as Jane Doe. The user has a premium account.\",  # 以 Jane Doe 称呼用户，并且用户拥有高级账户\n",
    ")\n",
    "\n",
    "print(\"Run completed with status: \" + run.status)  # 打印执行流的完成状态\n",
    "\n",
    "# 如果执行流状态为 \"completed\"（已完成），则获取并打印所有消息\n",
    "if run.status == \"completed\":\n",
    "    messages = client.beta.threads.messages.list(thread_id=thread.id)\n",
    "\n",
    "    print(\"\\nMessages:\\n\")\n",
    "    for message in messages:\n",
    "        assert message.content[0].type == \"text\"\n",
    "        print(f\"Role: {message.role.capitalize()}\")  # 角色名称首字母大写\n",
    "        print(\"Message:\")\n",
    "        print(message.content[0].text.value + \"\\n\")  # 每条消息后添加空行以增加可读性"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea5e1bca-3401-4db8-b3ae-b2797d11680b",
   "metadata": {},
   "source": [
    "### 通过 Assistant ID 删除指定助手"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "7535ee48-2107-465d-b5fa-b12356ba8b87",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AssistantDeleted(id='asst_EVvq2aGMIjOq8PXEoXPayUhj', deleted=True, object='assistant.deleted')"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 删除创建的助手\n",
    "client.beta.assistants.delete(assistant.id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "025b777a-d279-4c62-8a50-7d24a1baaa5a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "929b787f-372b-4c35-9769-381d41c91042",
   "metadata": {},
   "source": [
    "### 使用流式输出实现数学辅导老师"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "b68ff9fa-e815-444b-b9e3-9dc062a0cc00",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "starting run stream\n",
      "\n",
      "assistant > Of course, Jane Doe. To solve for \\( x \\) in the equation \\( 3x + 11 = 14 \\), you need to isolate \\( x \\) on one side of the equation. Here's how you can do it step by step:\n",
      "\n",
      "1. Subtract 11 from both sides of the equation to get \\( 3x \\) by itself on one side:\n",
      "\\[ 3x + 11 - 11 = 14 - 11 \\]\n",
      "\n",
      "2. This simplifies to:\n",
      "\\[ 3x = 3 \\]\n",
      "\n",
      "3. Now divide both sides of the equation by 3 to solve for \\( x \\):\n",
      "\\[ \\frac{3x}{3} = \\frac{3}{3} \\]\n",
      "\n",
      "4. This simplifies further to:\n",
      "\\[ x = 1 \\]\n",
      "\n",
      "So the solution to the equation \\( 3x + 11 = 14 \\) is \\( x = 1 \\).\n",
      "\n",
      "Would you like me to demonstrate how to perform these calculations using Python for verification?"
     ]
    },
    {
     "data": {
      "text/plain": [
       "AssistantDeleted(id='asst_siJSlBRLiyBo1pBLZbIX86EM', deleted=True, object='assistant.deleted')"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 官方案例\n",
    "from typing_extensions import override\n",
    "from openai import AssistantEventHandler\n",
    "import openai\n",
    "\n",
    "# 从环境变量 OPENAI_API_KEY 中获取 API 密钥\n",
    "client = openai.OpenAI()\n",
    "\n",
    "# 创建一个名为 \"Math Tutor\" 的助手，它是一个个人数学辅导老师。这个助手能够编写并运行代码来解答数学问题。\n",
    "assistant = client.beta.assistants.create(\n",
    "    name=\"Math Tutor\",\n",
    "    instructions=\"You are a personal math tutor. Write and run code to answer math questions.\",\n",
    "    tools=[{\"type\": \"code_interpreter\"}],  # 工具包括代码解释器\n",
    "    model=\"gpt-4-1106-preview\",  # 使用的模型是 GPT-4\n",
    ")\n",
    "\n",
    "# 创建一个交流线程\n",
    "thread = client.beta.threads.create()\n",
    "\n",
    "# 在该线程中创建一条消息，表示用户角色，并提交一个数学问题：“我需要解方程 `3x + 11 = 14`。你能帮忙吗？”\n",
    "message = client.beta.threads.messages.create(\n",
    "    thread_id=thread.id,\n",
    "    role=\"user\",\n",
    "    content=\"I need to solve the equation `3x + 11 = 14`. Can you help me?\",\n",
    ")\n",
    "\n",
    "print(\"starting run stream\")  # 打印开始执行流的消息\n",
    "\n",
    "# First, we create a EventHandler class to define\n",
    "# how we want to handle the events in the response stream.\n",
    " \n",
    "class EventHandler(AssistantEventHandler):    \n",
    "  @override\n",
    "  def on_text_created(self, text) -> None:\n",
    "    print(f\"\\nassistant > \", end=\"\", flush=True)\n",
    "      \n",
    "  @override\n",
    "  def on_text_delta(self, delta, snapshot):\n",
    "    print(delta.value, end=\"\", flush=True)\n",
    "      \n",
    "  def on_tool_call_created(self, tool_call):\n",
    "    print(f\"\\nassistant > {tool_call.type}\\n\", flush=True)\n",
    "  \n",
    "  def on_tool_call_delta(self, delta, snapshot):\n",
    "    if delta.type == 'code_interpreter':\n",
    "      if delta.code_interpreter.input:\n",
    "        print(delta.code_interpreter.input, end=\"\", flush=True)\n",
    "      if delta.code_interpreter.outputs:\n",
    "        print(f\"\\n\\noutput >\", flush=True)\n",
    "        for output in delta.code_interpreter.outputs:\n",
    "          if output.type == \"logs\":\n",
    "            print(f\"\\n{output.logs}\", flush=True)\n",
    " \n",
    "# Then, we use the `stream` SDK helper \n",
    "# with the `EventHandler` class to create the Run \n",
    "# and stream the response.\n",
    " \n",
    "with client.beta.threads.runs.stream(\n",
    "  thread_id=thread.id,\n",
    "  assistant_id=assistant.id,\n",
    "  instructions=\"Please address the user as Jane Doe. The user has a premium account.\",\n",
    "  event_handler=EventHandler(),\n",
    ") as stream:\n",
    "  stream.until_done()\n",
    "\n",
    "\n",
    "# 删除创建的助手\n",
    "client.beta.assistants.delete(assistant.id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ff800570-5539-43a2-8c36-f6e7958c112a",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "070e5f61-1931-46b6-a025-72da8116a125",
   "metadata": {},
   "source": [
    "## 开发 Python 代码小助手"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "e0604c6b-5227-454a-a036-3cbe8f071d7e",
   "metadata": {},
   "outputs": [],
   "source": [
    "import openai  # 导入 openai 库\n",
    "import time\n",
    "\n",
    "# 从环境变量 OPENAI_API_KEY 中获取 API 密钥\n",
    "client = openai.OpenAI()\n",
    "\n",
    "# 创建一个名为 \"Python Master\" 的助手，它能根据需求生成可以运行的 Python 代码\n",
    "assistant_python = client.beta.assistants.create(\n",
    "    name=\"Python Master\",\n",
    "    instructions=\"You are a Python Expert. Generate runnable Python code according to messages.\",\n",
    "    tools=[{\"type\": \"code_interpreter\"}],  # 使用工具：代码解释器\n",
    "    model=\"gpt-4o\",  # 使用模型： GPT-4\n",
    ")\n",
    "\n",
    "# 创建一个交流线程\n",
    "thread_python = client.beta.threads.create()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "ca4de29a-c87f-4f4a-9034-9aed4a82f641",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'asst_oB01W2lzBFO4YQgIn5QldOLd'"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "assistant_python.id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "0ad0533f-519f-40a0-97ed-73b235f2c18a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'thread_glOKBynaIzmlEL2BMDFYIzkt'"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "thread_python.id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "610371e1-82bf-47e5-bbb4-63f3bec8e7f7",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在该线程中创建一条信息\n",
    "message = client.beta.threads.messages.create(\n",
    "    thread_id=thread_python.id,\n",
    "    role=\"user\",\n",
    "    content=\"快速排序咋个写？\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "076da137-0c5e-4836-bb3e-663c81a2790e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'msg_FkPrssBSOS5uDEQMGF6IeiHK'"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "message.id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "ae385730-7d50-45ca-af53-748cf641a1a7",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Run completed with status: completed\n"
     ]
    }
   ],
   "source": [
    "# 创建并等待执行流完成，用于处理该线程中的交互和问题解答\n",
    "# 方式一：create_and_poll创建并轮询方式\n",
    "run = client.beta.threads.runs.create_and_poll(\n",
    "    thread_id=thread_python.id,\n",
    "    assistant_id=assistant_python.id,\n",
    ")\n",
    "\n",
    "print(\"Run completed with status: \" + run.status)  # 打印执行流的完成状态"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "a2bd2fdf-9adb-4bb9-8f34-00e360fbf787",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'run_v7Q9TffTwXB2y7CCPuX5yPdB'"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "run.id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "63c02863-5c7a-4582-969d-9a589a52d1e9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Run初始状态 queued\n"
     ]
    }
   ],
   "source": [
    "# 方式二：create 和 retrieve方式，判断run状态为（初始为queued）\n",
    "run2 = client.beta.threads.runs.create(\n",
    "    thread_id=thread_python.id,\n",
    "    assistant_id=assistant_python.id,\n",
    ")\n",
    "\n",
    "print(\"Run初始状态 \" + run2.status)  # 打印执行流的完成状态"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "ea30fc51-3251-48fe-ba2b-48c121b0f086",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'run_1vaQWkvblJuY7h3o9oE6kJ4A'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "run2.id"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "8745aff3-5e6c-43b3-9532-0ed47ed3d471",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Run2 completed with status: completed\n"
     ]
    }
   ],
   "source": [
    "while run2.status == \"queued\" or run.status == \"in_progress\":\n",
    "    run2 = client.beta.threads.runs.retrieve(\n",
    "        thread_id=thread_python.id,\n",
    "        run_id=run2.id\n",
    "    )\n",
    "    time.sleep(1)\n",
    "print(\"Run2 completed with status: \" + run2.status)  # 打印执行流的完成状态"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "83469189-458d-4130-9e92-a814043ff813",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Messages:\n",
      "\n",
      "Role: Assistant\n",
      "Message:\n",
      "这里是快速排序的结果：\n",
      "\n",
      "- 原始数组: [3, 6, 8, 10, 1, 2, 1]\n",
      "- 排序后的数组: [1, 1, 2, 3, 6, 8, 10]\n",
      "\n",
      "你可以将这个函数应用于其他的数组列表来进行排序。如果你有任何进一步的问题或者想了解更多，随时告诉我！\n",
      "\n",
      "Role: Assistant\n",
      "Message:\n",
      "快速排序（Quicksort）是一种高效的排序算法，使用分治法来将一个列表分成两个子列表，再递归地排序子列表。以下是快速排序的一个简单实现：\n",
      "\n",
      "```python\n",
      "def quicksort(arr):\n",
      "    if len(arr) <= 1:\n",
      "        return arr\n",
      "    pivot = arr[len(arr) // 2]\n",
      "    left = [x for x in arr if x < pivot]\n",
      "    middle = [x for x in arr if x == pivot]\n",
      "    right = [x for x in arr if x > pivot]\n",
      "    return quicksort(left) + middle + quicksort(right)\n",
      "\n",
      "# 测试快速排序\n",
      "arr = [3,6,8,10,1,2,1]\n",
      "print(f\"原始数组: {arr}\")\n",
      "sorted_arr = quicksort(arr)\n",
      "print(f\"排序后的数组: {sorted_arr}\")\n",
      "```\n",
      "\n",
      "这个简单实现的快速排序包括以下几步：\n",
      "1. 选择一个基准值（pivot），通常选择中间的元素。\n",
      "2. 将数组分为三个部分：\n",
      "   - 小于基准值的部分（left）\n",
      "   - 等于基准值的部分（middle）\n",
      "   - 大于基准值的部分（right）\n",
      "3. 递归地对左部分和右部分进行快速排序，然后将结果合并起来。\n",
      "\n",
      "运行这段代码你可以看到数组从无序状态变为有序状态。你要试着运行这段代码吗？\n",
      "\n",
      "Role: User\n",
      "Message:\n",
      "快速排序咋个写？\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 如果执行流状态为 \"completed\"（已完成），则获取并打印所有消息\n",
    "if run.status == \"completed\":\n",
    "    messages = client.beta.threads.messages.list(thread_id=thread_python.id)\n",
    "\n",
    "    print(\"\\nMessages:\\n\")\n",
    "    for message in messages:\n",
    "        assert message.content[0].type == \"text\"\n",
    "        print(f\"Role: {message.role.capitalize()}\")  # 角色名称首字母大写\n",
    "        print(\"Message:\")\n",
    "        print(message.content[0].text.value + \"\\n\")  # 每条消息后添加空行以增加可读性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "f2b351d8-8af7-401d-936b-377acfad2b2e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在该线程中创建一条信息\n",
    "message = client.beta.threads.messages.create(\n",
    "    thread_id=thread_python.id,\n",
    "    role=\"user\",\n",
    "    content=\"红黑树呢？\",\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "a664dc7f-399c-4793-95a0-1bca7b37847c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Run completed with status: completed\n"
     ]
    }
   ],
   "source": [
    "# 创建并等待执行流完成，用于处理该线程中的交互和问题解答\n",
    "run = client.beta.threads.runs.create_and_poll(\n",
    "    thread_id=thread_python.id,\n",
    "    assistant_id=assistant_python.id,\n",
    ")\n",
    "\n",
    "print(\"Run completed with status: \" + run.status)  # 打印执行流的完成状态"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "4a76261f-aae9-499e-91d8-0ffc55de8bd3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Messages:\n",
      "\n",
      "Role: Assistant\n",
      "Message:\n",
      "红黑树是一种自平衡二叉查找树，它能够保证插入、删除、查找的时间复杂度都是 \\(O(\\log n)\\)。对于实现红黑树来说，它要遵循以下的五个特性：\n",
      "\n",
      "1. 每个节点是红色的或是黑色的。\n",
      "2. 根节点是黑色的。\n",
      "3. 每个叶子节点（NIL节点）是黑色的。\n",
      "4. 如果一个节点是红色的，则它的两个子节点都是黑色的。\n",
      "5. 对每个节点，从该节点到其所有后代叶子节点的简单路径都包含相同数目的黑色节点。\n",
      "\n",
      "红黑树的完整实现相对比较复杂。下面是一个简单的红黑树实现的示例代码：\n",
      "\n",
      "```python\n",
      "class RedBlackNode:\n",
      "    def __init__(self, key, color='red'):\n",
      "        self.key = key\n",
      "        self.color = color  # 'red' or 'black'\n",
      "        self.left = None\n",
      "        self.right = None\n",
      "        self.parent = None\n",
      "\n",
      "class RedBlackTree:\n",
      "    def __init__(self):\n",
      "        self.TNULL = RedBlackNode(0)\n",
      "        self.TNULL.color = 'black'\n",
      "        self.root = self.TNULL\n",
      "\n",
      "    def insert(self, key):\n",
      "        # Normal BST insert\n",
      "        node = RedBlackNode(key)\n",
      "        node.left = self.TNULL\n",
      "        node.right = self.TNULL\n",
      "        node.parent = None\n",
      "        node.color = 'red'\n",
      "\n",
      "        y = None\n",
      "        x = self.root\n",
      "\n",
      "        while x != self.TNULL:\n",
      "            y = x\n",
      "            if node.key < x.key:\n",
      "                x = x.left\n",
      "            else:\n",
      "                x = x.right\n",
      "\n",
      "        node.parent = y\n",
      "        if y == None:\n",
      "            self.root = node\n",
      "        elif node.key < y.key:\n",
      "            y.left = node\n",
      "        else:\n",
      "            y.right = node\n",
      "\n",
      "        if node.parent == None:\n",
      "            node.color = 'black'\n",
      "            return\n",
      "\n",
      "        if node.parent.parent == None:\n",
      "            return\n",
      "\n",
      "        self.fix_insert(node)\n",
      "\n",
      "    def fix_insert(self, k):\n",
      "        # Fix the tree\n",
      "        while k.parent.color == 'red':\n",
      "            if k.parent == k.parent.parent.right:\n",
      "                u = k.parent.parent.left\n",
      "                if u.color == 'red':\n",
      "                    u.color = 'black'\n",
      "                    k.parent.color = 'black'\n",
      "                    k.parent.parent.color = 'red'\n",
      "                    k = k.parent.parent\n",
      "                else:\n",
      "                    if k == k.parent.left:\n",
      "                        k = k.parent\n",
      "                        self.right_rotate(k)\n",
      "                    k.parent.color = 'black'\n",
      "                    k.parent.parent.color = 'red'\n",
      "                    self.left_rotate(k.parent.parent)\n",
      "            else:\n",
      "                u = k.parent.parent.right\n",
      "                if u.color == 'red':\n",
      "                    u.color = 'black'\n",
      "                    k.parent.color = 'black'\n",
      "                    k.parent.parent.color = 'red'\n",
      "                    k = k.parent.parent\n",
      "                else:\n",
      "                    if k == k.parent.right:\n",
      "                        k = k.parent\n",
      "                        self.left_rotate(k)\n",
      "                    k.parent.color = 'black'\n",
      "                    k.parent.parent.color = 'red'\n",
      "                    self.right_rotate(k.parent.parent)\n",
      "            if k == self.root:\n",
      "                break\n",
      "        self.root.color = 'black'\n",
      "\n",
      "    def left_rotate(self, x):\n",
      "        y = x.right\n",
      "        x.right = y.left\n",
      "        if y.left != self.TNULL:\n",
      "            y.left.parent = x\n",
      "\n",
      "        y.parent = x.parent\n",
      "        if x.parent == None:\n",
      "            self.root = y\n",
      "        elif x == x.parent.left:\n",
      "            x.parent.left = y\n",
      "        else:\n",
      "            x.parent.right = y\n",
      "        y.left = x\n",
      "        x.parent = y\n",
      "\n",
      "    def right_rotate(self, x):\n",
      "        y = x.left\n",
      "        x.left = y.right\n",
      "        if y.right != self.TNULL:\n",
      "            y.right.parent = x\n",
      "\n",
      "        y.parent = x.parent\n",
      "        if x.parent == None:\n",
      "            self.root = y\n",
      "        elif x == x.parent.right:\n",
      "            x.parent.right = y\n",
      "        else:\n",
      "            x.parent.left = y\n",
      "        y.right = x\n",
      "        x.parent = y\n",
      "\n",
      "    def inorder_helper(self, node):\n",
      "        if node != self.TNULL:\n",
      "            self.inorder_helper(node.left)\n",
      "            print(node.key, end=' ')\n",
      "            self.inorder_helper(node.right)\n",
      "\n",
      "    def inorder(self):\n",
      "        self.inorder_helper(self.root)\n",
      "        print()\n",
      "\n",
      "# 测试红黑树\n",
      "rb_tree = RedBlackTree()\n",
      "numbers = [20, 15, 25, 10, 5]\n",
      "for number in numbers:\n",
      "    rb_tree.insert(number)\n",
      "\n",
      "rb_tree.inorder()\n",
      "```\n",
      "\n",
      "这个代码片段展示了红黑树的插入操作及其相关的修复操作。我们也实现了一个中序遍历的方法来验证树的结构是否正确。\n",
      "\n",
      "运行这段代码可以看到红黑树的结构输出。你想试试运行它吗？\n",
      "\n",
      "Role: User\n",
      "Message:\n",
      "红黑树呢？\n",
      "\n",
      "Role: Assistant\n",
      "Message:\n",
      "这里是快速排序的结果：\n",
      "\n",
      "- 原始数组: [3, 6, 8, 10, 1, 2, 1]\n",
      "- 排序后的数组: [1, 1, 2, 3, 6, 8, 10]\n",
      "\n",
      "你可以将这个函数应用于其他的数组列表来进行排序。如果你有任何进一步的问题或者想了解更多，随时告诉我！\n",
      "\n",
      "Role: Assistant\n",
      "Message:\n",
      "快速排序（Quicksort）是一种高效的排序算法，使用分治法来将一个列表分成两个子列表，再递归地排序子列表。以下是快速排序的一个简单实现：\n",
      "\n",
      "```python\n",
      "def quicksort(arr):\n",
      "    if len(arr) <= 1:\n",
      "        return arr\n",
      "    pivot = arr[len(arr) // 2]\n",
      "    left = [x for x in arr if x < pivot]\n",
      "    middle = [x for x in arr if x == pivot]\n",
      "    right = [x for x in arr if x > pivot]\n",
      "    return quicksort(left) + middle + quicksort(right)\n",
      "\n",
      "# 测试快速排序\n",
      "arr = [3,6,8,10,1,2,1]\n",
      "print(f\"原始数组: {arr}\")\n",
      "sorted_arr = quicksort(arr)\n",
      "print(f\"排序后的数组: {sorted_arr}\")\n",
      "```\n",
      "\n",
      "这个简单实现的快速排序包括以下几步：\n",
      "1. 选择一个基准值（pivot），通常选择中间的元素。\n",
      "2. 将数组分为三个部分：\n",
      "   - 小于基准值的部分（left）\n",
      "   - 等于基准值的部分（middle）\n",
      "   - 大于基准值的部分（right）\n",
      "3. 递归地对左部分和右部分进行快速排序，然后将结果合并起来。\n",
      "\n",
      "运行这段代码你可以看到数组从无序状态变为有序状态。你要试着运行这段代码吗？\n",
      "\n",
      "Role: User\n",
      "Message:\n",
      "快速排序咋个写？\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 如果执行流状态为 \"completed\"（已完成），则获取并打印所有消息\n",
    "if run.status == \"completed\":\n",
    "    messages = client.beta.threads.messages.list(thread_id=thread_python.id)\n",
    "\n",
    "    print(\"\\nMessages:\\n\")\n",
    "    for message in messages:\n",
    "        assert message.content[0].type == \"text\"\n",
    "        print(f\"Role: {message.role.capitalize()}\")  # 角色名称首字母大写\n",
    "        print(\"Message:\")\n",
    "        print(message.content[0].text.value + \"\\n\")  # 每条消息后添加空行以增加可读性"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "76f126e2-64a2-4887-810c-b5059d5bcf56",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "AssistantDeleted(id='asst_oB01W2lzBFO4YQgIn5QldOLd', deleted=True, object='assistant.deleted')"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 删除创建的助手\n",
    "client.beta.assistants.delete(assistant_python.id)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "788179ec-d10e-4cbd-b18b-1cf2b5fa02ee",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "e49e1c65-626f-473c-80c9-2be33bc0a98f",
   "metadata": {},
   "source": [
    "## Homework: 将数学辅导老师和Python小助手的代码重构，实现类似 Playground 的对话输入体验"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "541ad829-e6c7-4316-ab2f-03005610fc86",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.14"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
